﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel.Syndication;
using System.Text;
using System.Xml;
using Wayloop.Blog.Core.Data;
using Wayloop.Blog.Core.Data.Entities;
using Wayloop.Blog.Core.Extensions;


namespace Wayloop.Blog.Core.Services.Impl
{
    public class FeedService : IFeedService
    {
        /// <summary>
        /// Gets or sets the <see cref="IConfigurationService"/> instance.
        /// </summary>
        /// <value>The <see cref="IConfigurationService"/> instance.</value>
        public IConfigurationService Configuration { get; set; }


        /// <summary>
        /// Gets or sets the <see cref="IPostRepository"/> instance.
        /// </summary>
        /// <value>The <see cref="IPostRepository"/> instance.</value>
        public IPostRepository PostRepository { get; private set; }


        /// <summary>
        /// Initializes a new instance of the <see cref="FeedService"/> class.
        /// </summary>
        /// <param name="postRepository">The <see cref="IPostRepository"/> instance.</param>
        public FeedService(IPostRepository postRepository)
        {
            PostRepository = postRepository;
        }


        /// <summary>
        /// Gets the ATOM 1.0 feed.
        /// </summary>
        /// <returns>A string containing the ATOM 1.0 feed.</returns>
        public string GetAtomFeed()
        {
            return GetFeedContent<Atom10FeedFormatter>();
        }


        private string GetFeedContent<T>() where T : SyndicationFeedFormatter
        {
            var xmlWriterSettings = new XmlWriterSettings {
                Indent = true,
                IndentChars = "    ",
            };

            var xmlOutput = new StringBuilder();
            using (XmlWriter xmlWriter = XmlWriter.Create(xmlOutput, xmlWriterSettings)) {
                if (xmlWriter == null) {
                    throw new InvalidOperationException();
                }

                SyndicationFeed syndicationFeed = GetSyndicationFeed();
                var feedFormatter = Activator.CreateInstance(typeof (T), syndicationFeed) as T;
                if (feedFormatter == null) {
                    throw new InvalidOperationException();
                }

                feedFormatter.WriteTo(xmlWriter);
            }

            return xmlOutput.ToString();
        }


        private SyndicationFeed GetSyndicationFeed()
        {
            DateTime lastUpdatedTime = DateTime.MinValue;
            IEnumerable<SyndicationItem> items = GetSyndicationItems(ref lastUpdatedTime);

            var feed = new SyndicationFeed {
                Title = new TextSyndicationContent(Configuration.Title),
                Description = new TextSyndicationContent(Configuration.Description),
                Id = "tag:thomasjo.com,2009:",
                Generator = "Wayloop.Blog",
                LastUpdatedTime = lastUpdatedTime,
                Items = items,
            };

            AddFeedLink(feed);

            return feed;
        }


        private void AddFeedLink(SyndicationFeed feed)
        {
            feed.Links.Add(new SyndicationLink {
                RelationshipType = "self",
                Uri = new Uri("http://thomasjo.com/feed/atom"),
            });
        }


        private IEnumerable<SyndicationItem> GetSyndicationItems(ref DateTime lastUpdatedTime)
        {
            IEnumerable<Post> posts = PostRepository.FindAllPublished(0, 20);
            var items = new List<SyndicationItem>(posts.Count());

            foreach (var post in posts) {
                if (post.ModifiedOn > lastUpdatedTime) {
                    lastUpdatedTime = post.ModifiedOn;
                }

                items.Add(CreateSyndicationItem(post));
            }

            return items;
        }


        private SyndicationItem CreateSyndicationItem(Post post)
        {
            var item = new SyndicationItem {
                Id = "tag:thomasjo.com,{0}:{1}".FormatWith(post.PublishedOn.Value.ToString("yyyy-MM-dd"), post.Id),
                Title = new TextSyndicationContent(post.Title),
                PublishDate = post.PublishedOn.Value,
                LastUpdatedTime = post.ModifiedOn,
                Content = SyndicationContent.CreateHtmlContent(post.Body),
            };

            AddItemLink(post, item);
            AddItemAuthor(item);

            return item;
        }


        private void AddItemLink(Post post, SyndicationItem item)
        {
            item.Links.Add(new SyndicationLink {
                RelationshipType = "alternate",
                Title = post.Title,
                Uri = new Uri(String.Concat("http://thomasjo.com/archive/", post.Slug)),
            });
        }


        private void AddItemAuthor(SyndicationItem item)
        {
            item.Authors.Add(new SyndicationPerson {
                Name = "Thomas Johansen"
            });
        }
    }
}